package com.autumn.chat.struct.blive;

import com.autumn.chat.util.ByteUtil;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

public class BLiveProto {

    private int packetLength = 0;
    private short headerLength = 16;
    private short version = 0;
    private int operation = 0;
    private int sequenceID = 0;
    private String body = null;

    // 长链接推送给我们的 数据包的整体
    private byte[] packet;

    /**
     *
     * @param operation 取值 BLiveOperation
     * @param body
     */
    public BLiveProto(int operation, String body) {
        this.operation = operation;
        this.body = body;
    }

    public BLiveProto(int packetLength, short headerLength, short version, int operation, int sequenceID, String body, byte[] packet) {
        this.packetLength = packetLength;
        this.headerLength = headerLength;
        this.version = version;
        this.operation = operation;
        this.sequenceID = sequenceID;
        this.body = body;
        this.packet = packet;
    }

    public BLiveProto(byte[] packet) {
        this.packet = packet;
    }

    /**
     * 制作 proto包
     * @return
     */
    public byte[] pack() {
        // 计算包体长度
        if (body != null) {
            byte[] bodyBytes = body.getBytes(StandardCharsets.UTF_8);
            packetLength = headerLength + bodyBytes.length;
        } else {
            packetLength = headerLength;
        }

        // 将内容拼接成字节码的proto包
        byte[] temp1 = ByteUtil.byteMerger(ByteUtil.intToByte(packetLength) , ByteUtil.shortToByte(headerLength));
        byte[] temp2 = ByteUtil.byteMerger(temp1, ByteUtil.shortToByte(version));
        byte[] temp3 = ByteUtil.byteMerger(temp2, ByteUtil.intToByte(operation));
        byte[] temp4 = ByteUtil.byteMerger(temp3, ByteUtil.intToByte(sequenceID));
        if (body == null) {
            return temp4;
        }
        return ByteUtil.byteMerger(temp4, body.getBytes(StandardCharsets.UTF_8));
    }

    /**
    * Description: 解包 将 字节数组转化为对象 这里不计算Version为2 的数据包
    * @param
    * @return: com.autumn.chat.struct.blive.BLiveProto
    * @author: Shen_Yue
    * @Date: 18:07 2023/3/3
    */
    public BLiveProto unPack() {
        if (packet == null || packet.length == 0) {
            throw new RuntimeException("unPack proto 解包失败, 包体位空");
        }

        if (packet.length < 16) {
            throw new RuntimeException("unPack proto 解包失败, 包体非法");
        }

        // 第0位 到 第3位 是 PacketLength
        byte[] packetLengthByte = ByteUtil.subArray(packet, 0, 3);
        this.packetLength =  ByteBuffer.wrap(packetLengthByte).getInt();

        // 第4位 到 第5位 是 HeaderLength
        byte[] headerLengthByte = ByteUtil.subArray(packet, 4, 5);
        this.headerLength =  ByteBuffer.wrap(headerLengthByte).getShort();

        // 第6位 到 第7位 是 Version
        byte[] versionByte = ByteUtil.subArray(packet, 6, 7);
        this.headerLength =  ByteBuffer.wrap(versionByte).getShort();

        // 第8位 到 第11位 是 Operation
        byte[] operationByte = ByteUtil.subArray(packet, 8, 11);
        this.operation =  ByteBuffer.wrap(operationByte).getInt();

        // 第12位 到 第15位 是 SequenceID
        byte[] sequenceIdByte = ByteUtil.subArray(packet, 12, 15);
        this.sequenceID =  ByteBuffer.wrap(sequenceIdByte).getInt();

        // 第16位 到 末尾 是 body
        if (packet.length == 16) {
            // 判断有没有body
            return this;
        }
        int bodyEndPosition = packet.length - 1;
        byte[] bodyByte = ByteUtil.subArray(packet, 16, bodyEndPosition);
        this.body =  new String(bodyByte , StandardCharsets.UTF_8);

        return this;
    }

    @Override
    public String toString() {
        return "BLiveProto{" +
                "packetLength=" + packetLength +
                ", headerLength=" + headerLength +
                ", version=" + version +
                ", operation=" + operation +
                ", sequenceID=" + sequenceID +
                ", body='" + body + '\'' +
                '}';
    }

    public int getPacketLength() {
        return packetLength;
    }

    public short getHeaderLength() {
        return headerLength;
    }

    public short getVersion() {
        return version;
    }

    public int getOperation() {
        return operation;
    }

    public int getSequenceID() {
        return sequenceID;
    }

    public String getBody() {
        return body;
    }

    public byte[] getPacket() {
        return packet;
    }

    public void setPacket(byte[] packet) {
        this.packet = packet;
    }
}
